# coding=utf-8

import asyncio
from cmath import e
import numpy as np
import random
import time
import json

import platform
envTest = True if platform.system() == "Windows" else False # True为windows端的测试环境，False为原型机上的生产环境
if not envTest:
    import RPi.GPIO as GPIO

    GPIO.setmode(GPIO.BCM)

    # *****************GPIO定义******************
    pin_GPIO_BCM_SW_VG = 13
    pin_GPIO_BCM_SW_VD = 19
    GPIO.setup(pin_GPIO_BCM_SW_VG, GPIO.OUT)
    GPIO.setup(pin_GPIO_BCM_SW_VD, GPIO.OUT)
    GPIO.output(pin_GPIO_BCM_SW_VG, GPIO.LOW)
    GPIO.output(pin_GPIO_BCM_SW_VD, GPIO.LOW)


    def IO_ctrl(ch, sw):
        pin_GPIO_BCM_A0 = 24
        pin_GPIO_BCM_A1 = 25
        pin_GPIO_BCM_A2 = 5
        pin_GPIO_BCM_EN = 12
        pin_GPIO_BCM_IN = 6

        channel = {"10": 0b1111, "11": 0b1101, "12": 0b1011, "13": 0b1001, "6": 0b0111, "5": 0b0101, "4": 0b0011,
                   "3": 0b0001, "format": "A2A1A0EN"}
        switch = {"on": 0b00, "off": 0b11}
        # 以下3，4，5，6，11，12，13，14代表焊盘上引脚名, on, off 代表后级选通
        chlist = ["3", "4", "5", "6", "10", "11", "12", "13", "init"]
        swlist = ["on", "off"]

        if ch not in chlist:
            return 1
        if sw not in swlist:
            return 1

        elif ch == 'init':
            GPIO.setup(pin_GPIO_BCM_EN, GPIO.OUT)
            GPIO.setup(pin_GPIO_BCM_A2, GPIO.OUT)
            GPIO.setup(pin_GPIO_BCM_A1, GPIO.OUT)
            GPIO.setup(pin_GPIO_BCM_A0, GPIO.OUT)
            GPIO.setup(pin_GPIO_BCM_IN, GPIO.OUT)
            GPIO.output(pin_GPIO_BCM_EN, GPIO.HIGH)
            GPIO.output(pin_GPIO_BCM_A2, GPIO.LOW)
            GPIO.output(pin_GPIO_BCM_A1, GPIO.LOW)
            GPIO.output(pin_GPIO_BCM_A0, GPIO.LOW)
            GPIO.output(pin_GPIO_BCM_IN, GPIO.HIGH)
            return 0

        GPIO.output(pin_GPIO_BCM_EN, GPIO.HIGH)
        if sw == 'on':
            GPIO.output(pin_GPIO_BCM_IN, GPIO.LOW)
        else:
            GPIO.output(pin_GPIO_BCM_IN, GPIO.HIGH)
        if channel[ch] & 0b0010 == 0:
            GPIO.output(pin_GPIO_BCM_A0, GPIO.LOW)
        else:
            GPIO.output(pin_GPIO_BCM_A0, GPIO.HIGH)
        if channel[ch] & 0b0100 == 0:
            GPIO.output(pin_GPIO_BCM_A1, GPIO.LOW)
        else:
            GPIO.output(pin_GPIO_BCM_A1, GPIO.HIGH)
        if channel[ch] & 0b1000 == 0:
            GPIO.output(pin_GPIO_BCM_A2, GPIO.LOW)
        else:
            GPIO.output(pin_GPIO_BCM_A2, GPIO.HIGH)
        time.sleep(0.001)
        GPIO.output(pin_GPIO_BCM_EN, GPIO.LOW)
        time.sleep(0.001)
        return 0

    IO_ctrl('init', 'off')########
    IO_ctrl('10', 'on')###########
    #IO_ctrl('init', 'on')


# ******************与硬件通讯的基础模块******************
sendmessage = None

if not envTest:
    import ADS1256
    import DAC8532

if not envTest:
    adc = ADS1256.ADS1256()
    dac = DAC8532.DAC8532()
    adc.ADS1256_init()



    # if DAC8532.DAC_VREF!=5:
    # DAC8532.DAC_VREF=5.18
    # print(f'DAC Vref set to 5.18 V')

    def Output(channel, volt, dac=dac):
        #volt = volt * 4.13 / 4.096  # Calibration

        if channel == 1:  # channel 0 or channel 1
            dac.DAC8532_Out_Voltage(0x34, volt)
        else:
            dac.DAC8532_Out_Voltage(0x30, volt)


    def dac_calibration():
        Output(0, 0)
        Output(1, 0)
        adc.ADS1256_SetMode(1)
        time.sleep(0.005)
        gate_y1 = adc.ADS1256_GetChannalValue(2) * 5.0 / 0x7FFFFF
        drain_y1 = adc.ADS1256_GetChannalValue(3) * 5.0 / 0x7FFFFF
        Output(0, 4.0)
        Output(1, 4.0)
        time.sleep(0.005)
        gate_y2 = adc.ADS1256_GetChannalValue(2) * 5.0 / 0x7FFFFF - 4.0
        drain_y2 = adc.ADS1256_GetChannalValue(3) * 5.0 / 0x7FFFFF - 4.0
        gate_k = (gate_y2 - gate_y1) / 4
        drain_k = (drain_y2 - drain_y1) / 4
        gate_b = gate_y1
        drain_b = drain_y1
        return gate_k, gate_b, drain_k, drain_b


    [G_k, G_b, D_k, D_b] = dac_calibration()


    def gate_err(vg):
        global G_k, G_b
        return G_k * vg + G_b


    def drain_err(vd):
        global D_k, D_b
        return D_k * vd + D_b


allmode = {}
refVg = 0


class Transcurve:
    def __init__(self):
        self.name = 'trans'
        self.fullName = '转移曲线'
        self.chlist = {"1": "3", "2": "4", "3": "5", "4": "6", "5": "10", "6": "11", "7": "12", "8": "13"}
        self.defaultPara = {
            'holdT': '5',  # Hold time for voltage pre-settling
            'exp_Ids': '0.05',
            'drainV': '0.1',  # ref AGND
            'gateV_begin': '-0.4',  # ref AGND
            'gateV_end': '0.9',  # ref AGND
            'stepV': '0.01',  # step volt of sweeping
            'stepT': '0.05',  # hold time for each step
            'settleT': '0.1',  # time before sample
            'AGND': '2.5'  # given by the particular LDO
        }
        self.changableParams = self.defaultPara
        self.model_para = dict()
        self.loadpara()

        # eCharts图表的设置参数，包括坐标轴，动画时间，是否显示标记等。
        # 熟悉eCharts架构的话可以自由编辑样式。
        self.eChartsSet = ''


        ##!!!!!!显示曲线的条数取决于series里头有几个{}!!!!!!!!!return的数据如果比这个多不会显示，少了没事。

    def loadpara(self):
        with open('temp.json', 'r', encoding="utf-8") as model_file:
            self.model_para = json.load(model_file)

        self.AGND = eval(self.changableParams['AGND'])
        self.drainV = eval(self.changableParams['drainV'])  # ref AGND
        self.gateV_begin = eval(self.changableParams['gateV_begin'])  # ref AGND
        self.gateV_end = eval(self.changableParams['gateV_end'])  # ref AGND
        self.stepV = eval(self.changableParams['stepV'])  # step volt of sweeping
        self.stepT = eval(self.changableParams['stepT'])  # hold time for each step
        self.settleT = eval(self.changableParams['settleT'])  # time before sample
        self.expIds = eval(self.changableParams['exp_Ids'])
        self.xCounts = 0  # 控制坐标轴宽度上限
        self.pre_holdT = eval(self.changableParams['holdT'])

    async def prepare(self, ):
        self.eChartsSet = '''{
            "xAxis": {
                "name": "Gate V (V)",
                "type": "value",
                "nameLocation": "middle",
                "nameTextStyle": {
                    "color": "#FFFFFF",
                    "fontSize": 16
                },
                "nameGap": 25,
                "axisLine": {
                    "lineStyle": {
                        "color": "#FFFFFF"
                    }
                },
                "axisLabel": {
                    "fontSize": 14
                },
                "axisTick": {
                    "inside": true
                },
                "splitLine": {
                    "show": false
                }
            },
            "yAxis": {
                "name": "Drain I (uA)",
                "nameLocation": "end",
                "nameTextStyle": {
                    "color": "#FFFFFF",
                    "fontSize": 16
                },
                "nameGap": 15,
                "axisLine": {
                    "lineStyle": {
                        "color": "#FFFFFF"
                    },
                    "onZero":false
                },
                "axisLabel": {
                    "fontSize": 14
                }
            },
            "legend":{
                "orient":"horizontal",
                "textStyle":{
                    "color":"white"
                },
                "y":"bottom",
                "icon":"circle"
            },
            "animationDurationUpdate": 100,
        '''
        s = "\"series\":["
        for i in self.model_para["channels"]:
            s += r'''{"name":"'''+"c"+i+r'''","showSymbol": false, "data": [], "type": "line", "smooth": true},'''
        s = s[:-1]+r']}'
        self.eChartsSet += s
        self.pinNum_drain = 1  # DAC pinNum giving drainV
        self.pinNum_source = 0  # ADC pinNum sensing osc
        self.pinNum_gate = 0  # DAC pinNum giving gateV
        self.pinNum_AGND = 1  # ADC pinNum recaliber AGND
        self.is_sweep_reverse = 0
        # do_abs_Id = False
        self.Vcc = 5
        # kR = 1E6

        global adc

        self.vd = self.drainV + self.AGND
       
        self.vg = self.gateV_begin + self.AGND
        self.ftSettle = self.settleT
        self.ftHold = self.stepT
        self.vmax = self.gateV_end - self.gateV_begin
        self.n = int(self.vmax / self.stepV)  # num of samp

        self.rs = []
        self.X = []
        self.cur_AGND = []
        self.Id = []
        self.Vg = []

        self.expVg = []
        self.expcnt = 0

        # self.refVg = 0
        # ***************AGND Pre-sampling**************

        preAGND = []
        self.nPreset = int(self.ftSettle / self.ftHold)
        if not envTest:
            adc.ADS1256_SetMode(1)
            for i in range(self.nPreset):
                # self.r = adc.ADS1256_GetAll()
                # preAGND.append(self.r[self.pinNum_AGND] * self.Vcc / 0x7fffff)

                #preAGND.append(adc.ADS1256_GetChannalValue(self.pinNum_AGND) * self.Vcc / 0x7fffff)

                #测试
                preAGND.append(adc.ADS1256_GetChannalValue(self.pinNum_AGND) * 5.0 / 0x7fffff)
                #测试

                await asyncio.sleep(self.ftHold)

        self.averAGND = np.mean(preAGND)
        self.AGND = self.averAGND

        # ***************Sweep Back**************
        if self.is_sweep_reverse:
            self.gateV_begin, self.gateV_end = self.gateV_end, self.gateV_begin

        # ****************Set Starting Voltage***************
        self.set_step = 0.01
        self.set_times_vg = int(self.gateV_begin / self.set_step)
        self.set_times_vd = int(self.drainV / self.set_step)
        if not envTest:
            Output(self.pinNum_gate, self.AGND)
            Output(self.pinNum_drain, self.AGND)
            GPIO.output(pin_GPIO_BCM_SW_VG, GPIO.HIGH)
            GPIO.output(pin_GPIO_BCM_SW_VD, GPIO.HIGH)

        if not envTest:
            for u in range(abs(self.set_times_vg)):
                Output(self.pinNum_gate, self.AGND + u / abs(self.set_times_vg) * self.gateV_begin)
                await asyncio.sleep(self.ftHold)

            for v in range(abs(self.set_times_vd)):
                Output(self.pinNum_drain, self.AGND + v / abs(self.set_times_vd) * self.drainV)
                await asyncio.sleep(self.ftHold)

            await asyncio.sleep(self.pre_holdT)

            self.vg = self.gateV_begin + self.AGND
            self.vd = self.drainV + self.AGND
                

            Output(self.pinNum_gate, self.vg - gate_err(self.vg))
            Output(self.pinNum_drain, self.vd - drain_err(self.vd))

        # for k in range(10):
        # await asyncio.sleep(self.ftSettle)
        # k += 1

        # await asyncio.sleep(self.ftSettle)
        self.lastAGND = self.AGND
        # loopI和loopN是控制循环的变量，通过continueLoop定义循环进行的方式
        self.loopI = 0
        self.loopN = self.n
        if not envTest:
            adc.ADS1256_SetMode(1)

    def isContinue(self):
        # 用于判断循环是否继续的表达式
        return self.loopI < self.loopN

    def afterLoop(self):
        # 单次循环之后的变量修改
        self.loopI += 1

    async def loopBody(self,i=None, n=None):
        # 载入循环控制变量
        if i == None:
            i = self.loopI
        if n == None:
            n = self.loopN
        if not envTest:
            adc.ADS1256_SetMode(1)

        # *************循环采集数据时自定义的代码*****************************
        self.X.append(i * self.vmax / n + self.gateV_begin)
        if not envTest:
            temp = i * self.vmax / n + self.vg
            Output(self.pinNum_gate, temp)
            self.Vg.append(temp-2.5)
            #########################
            #read = adc.ADS1256_GetAll();
            #self.Vg.append((read[2] - read[1]) / 0x7fffff * self.Vcc)
            # self.Vg.append(adc.ADS1256_GetChannalValue(0) * self.Vcc / 0x7fffff)

            self.Id.clear()
            for ch in self.model_para['channels']:
                IO_ctrl(self.chlist[ch], 'on')
                time.sleep(0.003)
                self.Id.append(adc.ADS1256_GetChannalValue(0) * self.Vcc / 0x7fffff)
                print(adc.ADS1256_GetChannalValue(0) * self.Vcc / 0x7fffff)

            if self.model_para['mode'] == 'single':
                global refVg
                if self.Id[-1] <= self.expIds and self.expcnt <= 3:
                    self.expVg.append(i * self.vmax / n + self.vg)
                    self.expcnt += 1
                elif self.Id[-1] <= self.expIds and self.expcnt == 4:
                    refVg = self.expVg[0]
                    # self.expVg.clear()
                    self.expcnt = 0
                else:
                    self.expVg.clear()
                    self.expcnt = 0

        # *******************************************************************
        # 输出的数据及格式，envTest为True时输出的是随机产生的模拟数据
        # !!!!!!如果显示多条曲线可以用类似的结构，记得修改init部分self.option里的内容
        time.sleep(0.05)

        ret = []
        if envTest:
            ret.append(self.X[-1])
            for i in range(8):
                ret.append(random.random())
            return str(ret)
        else:
            # return "[{}, {}]".format(self.Vg[-1], self.Id[0])
            ret.append(self.Vg[-1])
            ret += self.Id
            return str(ret)

    # 循环结束后的操作
    async def endLoop(self, ):
        # ****************Set Ending Voltage**********
        self.reset_step = 0.01
        self.reset_times_vg = int(self.gateV_end / self.reset_step)
        self.reset_times_vd = int(self.drainV / self.reset_step)

        if not envTest:
            await asyncio.sleep(self.ftSettle)
            for i in range(abs(self.reset_times_vg)):
                temp = (self.gateV_end + self.AGND) - i / abs(self.reset_times_vg) * self.gateV_end
                Output(self.pinNum_gate, temp - gate_err(temp))
                await asyncio.sleep(self.ftHold)

            for k in range(abs(self.reset_times_vd)):
                temp = self.vd - k / abs(self.reset_times_vd) * self.drainV
                Output(self.pinNum_drain, temp - drain_err(temp))
                await asyncio.sleep(self.ftHold)

            Output(self.pinNum_drain, self.AGND - drain_err(self.AGND))
            Output(self.pinNum_gate, self.AGND - gate_err(self.AGND))

            GPIO.output(pin_GPIO_BCM_SW_VG, GPIO.LOW)
            GPIO.output(pin_GPIO_BCM_SW_VD, GPIO.LOW)

            await asyncio.sleep(self.ftSettle)
        # 这里要重置loopI的值
        self.loopI = 0

    def get_alg(self):
        return self.model_para


# 将定义的工作模式放入allmode中，可以通过注释来开启和关闭这个工作模式
allmode['#trans'] = Transcurve()


class Idvt:
    def __init__(self):
        self.name = 'idvt'
        self.fullName = '电流时间'
        self.chlist = {"1": "3", "2": "4", "3": "5", "4": "6", "5": "10", "6": "11", "7": "12", "8": "13"}

        self.defaultPara = {
            'AGND': '2.5',  # given by the particular LDO
            'drainV': '0.1',  # ref AGND
            'gateV': '0',  # ref AGND
            'stepT': '0.1',  # step volt of sweeping
            'settleT': '2',  # time before sample
            'x_width': '30'  # time before sample
        }
        self.changableParams = self.defaultPara
        self.model_para = dict()
        self.loadpara()

        # eCharts图表的设置参数，包括坐标轴，动画时间，是否显示标记等。
        # 熟悉eCharts架构的话可以自由编辑样式。
        self.eChartsSet = ''

    def loadpara(self):
        with open('temp.json', 'r',encoding="utf-8") as model_file:
            self.model_para = json.load(model_file)

        self.AGND = eval(self.changableParams['AGND'])
        self.drainV = eval(self.changableParams['drainV'])  # ref AGND
        self.gateV = eval(self.changableParams['gateV'])  # ref AGND
        self.stepT = eval(self.changableParams['stepT'])  # hold time for each step
        self.settleT = eval(self.changableParams['settleT'])  # time before sample
        self.xCounts = eval(self.changableParams['x_width']) / self.stepT  # 控制坐标轴宽度上限

    async def prepare(self):
        self.eChartsSet = '''{
            "xAxis": {
                "name": "时间(s)",
                "type": "time",
                "nameLocation": "middle",
                "nameTextStyle": {
                    "color": "#FFFFFF",
                    "fontSize": 16
                },
                "nameGap": 28,
                "axisLine": {
                    "lineStyle": {
                        "color": "#FFFFFF"
                    }
                },
                "axisLabel": {
                    "fontSize": 14,
                    "formatter": "{ss}"
                },
                "axisTick": {
                    "inside": true
                },
                "splitLine": {
                    "show": false
                }
            },
            "yAxis": {
                "name": "电流(uA)",
                "nameLocation": "end",
                "nameTextStyle": {
                    "color": "#FFFFFF",
                    "fontSize": 16
                },
                "nameGap": 15,
                "axisLine": {
                    "lineStyle": {
                        "color": "#FFFFFF"
                    }
                },
                "axisLabel": {
                    "fontSize": 14
                }
            },
            "legend":{
                "orient":"horizontal",
                "textStyle":{
                    "color":"white"
                },
                "y":"bottom",
                "icon":"circle"
            },
            "animationDurationUpdate": 0,
        '''
        s = "\"series\":["
        for i in self.model_para["channels"]:
            s += r'''{"name":"'''+"c"+i+r'''","showSymbol": false, "data": [], "type": "line", "smooth": true},'''
        s = s[:-1]+r']}'
        self.eChartsSet += s
        self.pinNum_drain = 1  # DAC pinNum giving drainV
        self.pinNum_source = 0  # ADC pinNum sensing osc
        self.pinNum_gate = 0  # DAC pinNum giving gateV
        self.pinNum_AGND = 1  # ADC pinNum recaliber AGND
        # self.is_sweep_reverse = 0
        # do_abs_Id = False
        self.Vcc = 5
        # kR = 1E6
        self.tare = 0

        global adc

        self.ftSettle = self.settleT
        self.ftHold = self.stepT

        # ***************AGND Pre-sampling**************
        if not envTest:
            adc.ADS1256_SetMode(1)
            preAGND = []
            self.nPreset = int(self.ftSettle / self.ftHold)
            for i in range(self.nPreset):
                preAGND.append(adc.ADS1256_GetChannalValue(self.pinNum_AGND) * self.Vcc / 0x7fffff)
                await asyncio.sleep(self.ftHold)

            self.AGND = np.mean(preAGND)

        # 先跑一遍转移曲线
        if envTest or self.model_para['mode'] == 'single':
            
            global refVg
            wMode = allmode['#trans']
            await wMode.prepare()
            while wMode.isContinue():
                await wMode.loopBody()
                wMode.afterLoop()
                
                await sendmessage('{}%'.format(int(wMode.loopI / wMode.loopN * 100)), 'trans')
            await wMode.endLoop()
            if self.gateV == 0 and abs(refVg - self.AGND) < 1:
                self.gateV = refVg - self.AGND

        await sendmessage('ExpVg: ' + '{}'.format(self.gateV))
        if not envTest:
            # ************测试完后注释掉*************** #
            if (abs(self.gateV)) > 1:
                print('gateV: {}'.format(self.gateV))
                self.gateV = 0
                print('protect!!!!')

            self.vd = self.drainV + self.AGND
            self.vg = self.gateV + self.AGND

            self.rs = []
            self.X = []
            self.cur_AGND = []
            self.Id = []
            self.Id_tared = []
            self.Vg = []

            # ****************Set Starting Voltage************
            self.set_step = 0.01
            self.set_times_vg = int(self.gateV / self.set_step)
            self.set_times_vd = int(self.drainV / self.set_step)

            Output(self.pinNum_gate, self.AGND)
            Output(self.pinNum_drain, self.AGND)
            GPIO.output(pin_GPIO_BCM_SW_VG, GPIO.HIGH)
            GPIO.output(pin_GPIO_BCM_SW_VD, GPIO.HIGH)

        
            await asyncio.sleep(self.ftSettle)
            for u in range(abs(self.set_times_vg)):
                temp = self.AGND + u / abs(self.set_times_vg) * self.gateV
                Output(self.pinNum_gate, temp - gate_err(temp))
                await asyncio.sleep(self.ftHold)

            for v in range(abs(self.set_times_vd)):
                temp = self.AGND + v / abs(self.set_times_vd) * self.drainV
                Output(self.pinNum_drain, temp - drain_err(temp))
                await asyncio.sleep(self.ftHold)

            await asyncio.sleep(5)

            Output(self.pinNum_gate, self.vg - gate_err(self.vg))
            Output(self.pinNum_drain, self.vd - drain_err(self.vd))

        await asyncio.sleep(self.ftSettle)
        await sendmessage('Gogogo!', 'start')
        self.timeOrigin = time.time()
        # loopI和loopN是控制循环的变量，通过continueLoop定义循环进行的方式
        self.loopI = 0
        self.loopN = 0

    def isContinue(self):
        # 用于判断循环是否继续的表达式
        return True  # 电流时间模式为无限循环，直到人工暂停或者停止

    def afterLoop(self):
        # 单次循环之后的变量修改
        self.loopI += 1

    async def loopBody(self,i=None, n=None):
        self.stop = 1
        # 载入循环控制变量
        if i == None:
            i = self.loopI
        if n == None:
            n = self.loopN
        Id = []
        Id_average = 0
        Id_tared = 0
        # *************循环采集数据时自定义的代码*****************************
        if not envTest:
            adc.ADS1256_SetMode(1)

            self.X.append(i * self.stepT)
        if not n == 'tare':  # 'tare'命令下不等待
            await asyncio.sleep(self.ftHold)
        if not envTest:
            read = adc.ADS1256_GetAll()
            self.Vg.append((read[2] - read[1]) / 0x7fffff * self.Vcc)
            # self.Vg.append(adc.ADS1256_GetChannalValue(0) * self.Vcc / 0x7fffff)
            for key in self.model_para['channels']:
                IO_ctrl(self.chlist[key], 'on')
                time.sleep(0.003)
                current_value = adc.ADS1256_GetChannalValue(0) / 0x7fffff * self.Vcc
                Id.append(current_value)

            Id_average = np.mean(Id)
            Id_tared = Id_average - self.tare

        if n == 'tare':
            if envTest:
                self.tare = 0
            else:
                self.tare = Id_average
            await sendmessage('{}'.format(self.tare), 'tare')
            return '{}'.format(self.tare)

        # 测试代码
        if not envTest:
            for i in range(1,8,1):
                print(read[i] / 0x7fffff * self.Vcc)
        # 测试代码

        # *******************************************************************
        # 输出的数据及格式，envTest为True时输出的是随机产生的模拟数据
        timepassed = time.time() - self.timeOrigin
        ret = []
        # 时间    通道1数据   通道2数据   ...     所有通道平均电流    xxx     xxx     栅压
        if not envTest and (self.X[-1] <= self.stop):
            ret.append(timepassed * 1000)
            ret += Id
            ret += [Id_average, self.X[-1] * 1000, self.tare, Id_tared, self.gateV]
            return str(ret)
        elif not envTest and (self.X[-1] > self.stop):
            ret.append(timepassed * 1000)
            ret += Id
            ret += [Id_average, self.X[-1] * 1000, self.tare, Id_tared, self.gateV]
            return str(ret)
        else:
            return "[{}, {:.3}, {:.3},{:.3}]".format(timepassed * 1000, random.random(), random.random(),
                                                     random.random())

    # 循环结束后的操作
    async def endLoop(self, ):
        # 这里要重置loopI的值
        await asyncio.sleep(self.ftSettle)
        self.loopI = 0
        self.tare = 0

        # **************Set Ending Voltage*************
        self.reset_step = 0.01
        self.reset_times_vg = int((self.gateV) / self.reset_step)
        self.reset_times_vd = int(self.drainV / self.reset_step)
        if not envTest:
            adc.ADS1256_SetMode(1)

        if not envTest:
            for i in range(abs(self.reset_times_vg)):
                Output(self.pinNum_gate, self.vg - i / abs(self.reset_times_vg) * self.gateV)
                await asyncio.sleep(self.ftHold)

            for k in range(abs(self.reset_times_vd)):
                Output(self.pinNum_drain, self.vd - k / abs(self.reset_times_vd) * self.drainV)
                await asyncio.sleep(self.ftHold)

            Output(self.pinNum_gate, self.AGND - gate_err(self.AGND))
            Output(self.pinNum_drain, self.AGND - drain_err(self.AGND))

            GPIO.output(pin_GPIO_BCM_SW_VG, GPIO.LOW)
            GPIO.output(pin_GPIO_BCM_SW_VD, GPIO.LOW)

        await asyncio.sleep(self.ftSettle)

    def get_alg(self):
        return self.model_para


# 将定义的工作模式放入allmode中，可以通过注释来开启和关闭这个工作模式
allmode['#idvt'] = Idvt()


class RandomData:
    def __init__(self):
        self.name = 'rnd'
        self.fullName = '模拟数据'
        self.defaultPara = {
            'start': '50',  # 随机数开始
            'jump': '5',  # 随机增减的范围
            'max': '100',  # 上限
            'min': '0',  # 下限
            'stepT': '0.1',  # 产生一个随机数的时间
            'x_width': '10'  # time before sample
        }
        self.changableParams = self.defaultPara
        self.loadpara()

        # eCharts图表的设置参数，包括坐标轴，动画时间，是否显示标记等。
        # 熟悉eCharts架构的话可以自由编辑样式。
        self.eChartsSet = r'''{
            "xAxis": {
                "name": "时间(s)",
                "type": "time",
                "nameLocation": "middle",
                "nameTextStyle": {
                    "color": "#FFFFFF",
                    "fontSize": 16
                },
                "nameGap": 28,
                "axisLine": {
                    "lineStyle": {
                        "color": "#FFFFFF"
                    }
                },
                "axisLabel": {
                    "fontSize": 14,
                    "formatter": "{ss}"
                },
                "axisTick": {
                    "inside": true
                },
                "splitLine": {
                    "show": false
                }
            },
            "yAxis": {
                "name": "模拟数据",
                "nameLocation": "end",
                "nameGap": 15
            },
            "animationDurationUpdate": 0,
            "series": [{
                "showSymbol": false,
                "data":[],
                "type":"line"
            }]
        }
        '''

    def loadpara(self):
        self.start = eval(self.changableParams['start'])
        self.jump = eval(self.changableParams['jump'])  # ref AGND
        self.max = eval(self.changableParams['max'])  # ref AGND
        self.min = eval(self.changableParams['min'])  # hold time for each step
        self.stepT = eval(self.changableParams['stepT'])  # time before sample
        self.xCounts = eval(self.changableParams['x_width']) / self.stepT  # 控制坐标轴宽度上限

    # 循环开始时的准备
    async def prepare(self, ):
        self.numNow = self.start
        # loopI和loopN是控制循环的变量，通过continueLoop定义循环进行的方式
        self.loopI = 0
        self.loopN = 0
        await asyncio.sleep(0.2)

    def isContinue(self):
        # 用于判断循环是否继续的表达式
        return True  # 电流时间模式为无限循环，直到人工暂停或者停止

    def afterLoop(self):
        # 单次循环之后的变量修改
        self.loopI += 1

    async def loopBody(self, i=None, n=None):
        # 载入循环控制变量
        if i == None:
            i = self.loopI
        if n == None:
            n = self.loopN
        # *************循环采集数据时自定义的代码*****************************
        import random
        res = self.numNow + random.random() * self.jump - 0.5 * self.jump
        if res > self.max: res = self.max
        if res < self.min: res = self.min
        self.numNow = res
        await asyncio.sleep(self.stepT)
        # *******************************************************************
        # 输出的数据及格式
        return "[{}, {}]".format(i * self.stepT * 1000, res)

    # 循环结束后的操作
    async def endLoop(self, ):
        # 这里要重置loopI的值
        self.loopI = 0

    # 将定义的工作模式放入allmode中，可以通过注释来开启和关闭这个工作模式


allmode['#rnd'] = RandomData()


class DeviceSet:
    def __init__(self):
        self.name = 'set'
        self.fullName = '采样设置'
        self.defaultPara = {
            '稳定时间': '180',
            '采样时间': '120',  # 随机增减的范围
        }
        self.changableParams = self.defaultPara
        self.loadpara()

        # eCharts图表的设置参数，包括坐标轴，动画时间，是否显示标记等。
        # 熟悉eCharts架构的话可以自由编辑样式。
        self.eChartsSet = r'''{

        }
        '''

    def loadpara(self):
        None

        # 循环开始时的准备

    async def prepare(self, ):
        None

    def isContinue(self):
        # 用于判断循环是否继续的表达式
        return False  # 电流时间模式为无限循环，直到人工暂停或者停止

    def afterLoop(self):
        # 单次循环之后的变量修改
        None

    async def loopBody(self, i=None, n=None):
        # 载入循环控制变量
        return "[{}, {}]".format(0, 0)

    # 循环结束后的操作
    async def endLoop(self, ):
        None

    # 将定义的工作模式放入allmode中，可以通过注释来开启和关闭这个工作模式


allmode['#set'] = DeviceSet()

# **********************运行参数的读取，设置，保存模块*************
import os


def modeConfig(mode='get', conf=None):
    if mode == 'get':
        res = {}
        for key in allmode.keys():
            name = allmode[key].name
            res[name] = {}
            res[name]['name'] = allmode[key].fullName
            res[name]['para'] = allmode[key].changableParams
        return res
    elif mode == 'default':
        for key in allmode.keys():
            allmode[key].changableParams = allmode[key].defaultPara
        return modeConfig()
    elif mode == 'set':
        for key in conf:
            # 如果载入参数失败会自动读取默认参数
            try:
                allmode['#' + key].changableParams = conf[key]['para']
                allmode['#' + key].loadpara()
            except:
                print('load para error!!!')
                None


# 读取config.ini配制文件，如果没有找到配制文件，则读取默认配制参数。
def savepara():
    import json
    with open('config.ini', 'w') as f:
        json.dump(modeConfig(), f,indent=4,ensure_ascii=False)
    


def loadpara():
    if not os.path.isfile('config.ini'):
        savepara()
    else:
        import json
        with open('config.ini', 'r', encoding="utf-8") as f:
            Params = json.load(f)
            modeConfig('set', Params)
        savepara()
